
package com.zebra.common.concurrent;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;


/**
 *
 * @Date 2020/2/29 0029
 **/
public class ZebraFixedTimeScheduler extends ScheduledThreadPoolExecutor {

    public ZebraFixedTimeScheduler(int corePoolSize){
        this(corePoolSize, "zebra-scheduler");
    }

    public ZebraFixedTimeScheduler(int corePoolSize, String threadName) {
        super(corePoolSize, new ZebraThreadFactory(threadName));
    }


    public ScheduledFuture<?> scheduleWithFixedTime(Runnable command,
                                                    long initDelay,
                                                    long delay,
                                                    int repeat,
                                                    TimeUnit unit) {
        if (repeat < 0) {
            repeat = 0;
        }
        FixedTimeFutureTask t = new FixedTimeFutureTask(command, repeat, delay, unit);
        t.delegate = schedule(t, initDelay, unit);
        return t;
    }


    private class FixedTimeFutureTask extends FutureTask<Void> implements RunnableScheduledFuture<Void> {
        final AtomicInteger leftTime;
        final long delay;
        final TimeUnit unit;
        private final Runnable runnable;
        volatile ScheduledFuture<?> delegate;


        FixedTimeFutureTask(Runnable runnable, int repeat, long delay, TimeUnit unit) {
            super(runnable, null);
            this.runnable = runnable;
            this.leftTime = new AtomicInteger(repeat);
            this.delay = delay;
            this.unit = unit;
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return delegate.getDelay(unit);
        }

        @Override
        public int compareTo(Delayed o) {
            return delegate.compareTo(o);
        }

        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            return delegate.cancel(mayInterruptIfRunning);
        }

        @Override
        public boolean isCancelled() {
            return delegate.isCancelled();
        }

        @Override
        public boolean isDone() {
            return delegate.isDone();
        }

        @Override
        public Void get() throws InterruptedException, ExecutionException {
            delegate.get();
            return null;
        }

        @Override
        public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            delegate.get(timeout, unit);
            return null;
        }

        @Override
        public boolean isPeriodic() {
            return false;
        }

        @Override
        protected void done() {
            if (!isCancelled() && leftTime.getAndDecrement() > 0) {
                this.delegate = schedule(new FutureTask<Void>(runnable, null) {
                    @Override
                    protected void done() {
                        FixedTimeFutureTask.this.done();
                    }
                }, delay, unit);
            }
        }

    }

}
